package gopool

import (
	"context"
	"gitee.com/ichub/goconfig/common/base/baseiface"
	"gitee.com/ichub/goconfig/common/base/baseutils"
	"gitee.com/ichub/goconfig/common/base/baseutils/goutils"

	pool "github.com/jolestar/go-commons-pool"
	"reflect"
	"time"
)

const maxtotal = 1000
const maxidle = 100

type GeneralObjectPool[T baseiface.IpoolObj] struct {
	CommonPool *pool.ObjectPool
}

// NewGeneralObjectPool 使用传入的上下文初始化连接池
func NewGeneralObjectPool[T baseiface.IpoolObj]() *GeneralObjectPool[T] {
	var msgPool = &GeneralObjectPool[T]{}
	return msgPool.init(context.Background())
}

func (gop *GeneralObjectPool[T]) init(ctx context.Context) *GeneralObjectPool[T] {
	PoolConfig := pool.NewDefaultPoolConfig()
	PoolConfig.MaxTotal = maxtotal
	PoolConfig.MaxIdle = maxidle

	WithAbandonedConfig := pool.NewDefaultAbandonedConfig()
	gop.CommonPool = pool.NewObjectPoolWithAbandonedConfig(ctx, pool.NewPooledObjectFactorySimple(
		func(ctx context.Context) (interface{}, error) {
			return gop.Link()
		}), PoolConfig, WithAbandonedConfig)
	return gop
}

// Link 初始化连接,通过指针类型初始化对象
func (gop *GeneralObjectPool[T]) Link() (T, error) {
	var ptr T
	var objType = reflect.TypeOf(ptr)
	if objType.Kind() != reflect.Ptr {
		return gop.NewOfType(), nil
	}
	var value = reflect.New(objType.Elem())
	return value.Interface().(T), nil
}
func (gop *GeneralObjectPool[T]) NewOfPtrType() T {
	var ptr T
	var objType = reflect.TypeOf(ptr)
	if objType.Kind() != reflect.Ptr {
		return gop.NewOfType()
	}
	var value = reflect.New(objType.Elem())
	var res = value.Interface().(T)
	res.Init()
	baseutils.IfProxy(res)
	return res

}
func (gop *GeneralObjectPool[T]) NewOfType() T {
	var ptr T
	ptr.Init()
	baseutils.IfProxy(&ptr)
	return ptr

}

// BorrowObject 从连接池借用对象，增加了错误处理和重试逻辑
func (gop *GeneralObjectPool[T]) BorrowObject(ctx context.Context) (T, error) {
	var inst T
	obj, err := gop.CommonPool.BorrowObject(ctx)
	if err != nil {
		goutils.Error("连接池获取对象失败", err)
		// 尝试重试逻辑
		time.Sleep(time.Second) // 简单示例，实际应用中可能需要更复杂的重试策略
		return inst, err
	}

	inst = obj.(T)
	baseutils.IfProxy(inst)
	inst.Init()

	return inst, nil
}

// ReturnObject 交还对象到连接池
func (gop *GeneralObjectPool[T]) ReturnObject(ctx context.Context, object T) error {
	object.Shutdown()
	var err = gop.CommonPool.ReturnObject(ctx, object)
	if err != nil {
		goutils.Error("返回对象到连接池失败", err)
	}
	return err
}
